﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SimpleRayTracer
{
    class Vector3D
    {
        public double x;
        public double y;
        public double z;

        public Vector3D()
        {
            x = y = z = 0.0;
        }

        public Vector3D(double x, double y, double z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public static double Dot(Vector3D v1, Vector3D v2)
        {
            double outValue = 0.0;

            outValue = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;

            return outValue;
        }

        public static Vector3D Cross(Vector3D v1, Vector3D v2)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.y * v2.z - v1.z * v2.y;
            outVect.y = v1.z * v2.x - v1.x * v2.z;
            outVect.z = v1.x * v2.y - v1.y * v2.x;

            return outVect;
        }

        public static Vector3D operator -(Vector3D v1, Vector3D v2)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.x - v2.x;
            outVect.y = v1.y - v2.y;
            outVect.z = v1.z - v2.z;

            return outVect;
        }

        public static Vector3D operator +(Vector3D v1, Vector3D v2)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.x + v2.x;
            outVect.y = v1.y + v2.y;
            outVect.z = v1.z + v2.z;

            return outVect;
        }

        public static Vector3D operator *(Vector3D v1, double scale)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.x * scale;
            outVect.y = v1.y * scale;
            outVect.z = v1.z * scale;

            return outVect;
        }

        public static Vector3D operator *(Vector3D v1, Vector3D v2)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.x * v2.x;
            outVect.y = v1.y * v2.y;
            outVect.z = v1.z * v2.z;

            return outVect;
        }

        public static Vector3D operator /(Vector3D v1, double scale)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.x / scale;
            outVect.y = v1.y / scale;
            outVect.z = v1.z / scale;

            return outVect;
        }

        public static Vector3D operator /(Vector3D v1, Vector3D v2)
        {
            Vector3D outVect = new Vector3D();

            outVect.x = v1.x / v2.x;
            outVect.y = v1.y / v2.y;
            outVect.z = v1.z / v2.z;

            return outVect;
        }

        public static double Modv(Vector3D v)
        {
            return System.Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
        }

        public static Vector3D Normv(Vector3D v)
        {
            Vector3D outVect = new Vector3D();
            double modulus = Modv(v);

            outVect.x = v.x / modulus;
            outVect.y = v.y / modulus;
            outVect.z = v.z / modulus;

            return outVect;
        }

        public static double GetCosAngleV1V2(Vector3D v1, Vector3D v2)
        {
            /* incident angle
             intersection pt (i)
            double ix, iy, iz;
            ix = px+t*vx;
            iy = py+t*vy;
            iz = pz+t*vz;
            normal at i
            double nx, ny, nz;
            nx = ix - cx;
            ny = iy - cy;
            nz = iz - cz;

            cos(t) = (v.w) / (|v|.|w|)
            */
            return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z) / (Modv(v1) *
                   Modv(v2));
        }
    }
}
